//
//  BrickSet.h
//  BrickSet
//
//  Created by Captain Black on 2016/11/29.
//  Copyright © 2016年 Captain Black. All rights reserved.
//

#import "BSService.h"

//! Project version number for BrickSet.
FOUNDATION_EXPORT double BrickSetVersionNumber;

//! Project version string for BrickSet.
FOUNDATION_EXPORT const unsigned char BrickSetVersionString[];

// In this header, you should import all the public headers of your framework using statements like #import <BrickSet/PublicHeader.h>

@interface BrickSet : NSObject

/// 注册绑定服务类与协议。只要服务类能遵从目标协议，同一个服务类可以注册绑定多个协议
/// @param cls 实现类
/// @param serviceProtocol 目标协议
+ (void)registerClass:(Class)cls forService:(Protocol *)serviceProtocol;

/// 注销服务。
/// @param serviceProtocol 目标协议
+ (void)unregisterService:(Protocol *)serviceProtocol;

/// 获取与目标协议绑定的服务实例。BrickSet 会以单例形式持有该实例。
/// @param serviceProtocol 目标协议
+ (id)instanceForService:(Protocol *)serviceProtocol;

/// 加载绑定的静态服务。使用dladdr函数通过内存地址获取目标模块的具体信息，在加载目标模块中绑定静态服务
/// @param addr 符号内存地址。地址可以为全局变量、函数、类 等符号的地址
+ (void)loadStaticBindingServicesByAddress:(const void*)addr;

/// 初始化所有静态绑定的服务
+ (void)initStaticBindingServices;

@end

// 注册绑定服务类与协议
#define BSServiceRegister(cls, serviceProtocol) \
    [BrickSet registerClass:cls forService:@protocol(serviceProtocol)]
// 注销目标协议绑定的服务
#define BSServiceUnregister(serviceProtocol) \
    [BrickSet unregisterService:(@protocol(serviceProtocol))]
// 通过协议获取服务实例
#define BSService(name) \
    ((id<name>)[BrickSet instanceForService:@protocol(name)])

struct BSServiceInfo {
    char* serviceName;
    char* impClassName;
    uint  priority;
};

#define BSServiceBind(_serviceProtocol_, _impClass_, _priority_)                                                    \
struct BSServiceInfo __BSServiceInfo_##_serviceProtocol_ __attribute((used, section("__DATA,__BSServiceInfo"))) = { \
    .serviceName = #_serviceProtocol_,                                                                              \
    .impClassName = #_impClass_,                                                                                    \
    .priority = _priority_,                                                                                         \
};
